package com.wyw.function.learning.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Title
 * @Description
 * @Author Mr Wu yewen.wu.china@gmail.com
 * Update History:
 * Author        Time            Content
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Shop {
    private String shopName;

    private static final Random r = new Random();

    private double calculatePrice(String product) {
        delay();
        return r.nextDouble() * product.charAt(0) + product.charAt(1);
    }

//    // 同步
//    public double getPrice(String shopName) {
//        delay();
//        return calculatePrice(shopName);
//    }

    // 演示对多个异步任务进行流水线操作使用
    public String getPrice(String shopName) {
        double price = calculatePrice(shopName);
        Discount.CODE code = Discount.CODE.values()[r.nextInt(Discount.CODE.values().length)];
        return String.format(shopName + ":" + price + ":" + code);
    }

    // 异步
    public Future<Double> getPriceAsync(String shopName) {
        CompletableFuture<Double> future = new CompletableFuture<>();
        new Thread(() -> {
            try {
                // 测试出现异常的i情况
//                int i = 1 / 0;
                double ca = calculatePrice(shopName);
                future.complete(ca);
            } catch (Exception ex) {
                // 如果出现异常了，进行异常的处理
                future.completeExceptionally(ex);
            }
        }).start();

        return future;
    }

    // 使用supplyAsync创建CompletableFuture
    public Future<Double> getPriceAsync2(String shopName) {
        // supplyAsync方法接收一个生产者（Supplier）作为参数，返回一个CompletableFuture对象，该对象完成异步执行后会读取调用生产者方法的返回值。
        // 生产者方法会交由ForkJoinPool池中某个执行线程（Executor）运行，但是你也可以使用supplyAsync重载版本，传毒第二个参数指定不同的执行线程执行生产者方法
//        return CompletableFuture.supplyAsync(() -> calculatePrice(shopName));
        return CompletableFuture.supplyAsync(() -> calculatePrice(shopName), Executors.newSingleThreadExecutor());
    }

    // 延迟方法
    private static void delay() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

